/*************  技术支持与购买说明    **************
产品主页：http://tw51.haohaodada.com
淘宝搜索：天问51，可购买。目前基础版99元，带彩屏标准备版149元，旗舰版299
技术支持QQ群一：1138055784
******************************************/

#ifndef __DHT11_H
#define __DHT11_H

#if defined (_C51)
#include <REG52.h>

#elif defined (_STC12)
#include <STC12X.h>
#include "STC12_delay.h"

#elif defined (_STC15)
#include <STC15X.h>
#include "STC15_delay.h"

#elif defined (_STC8)
#include <STC8HX.h>
#include "delay.h"

#else   //STC16
#include <STC16F.h>
#include "delay.h"

#endif

#ifndef DHT11_DQ
#define DHT11_DQ       	P4_6
#endif

#ifndef DHT11_DQ_MODE
#define DHT11_DQ_MODE	{P4M1&=~0x40;P4M0&=~0x40;}	//双向IO口
#endif

uint8 _dht11_arry_value[5];    //定义存取数组

uint8 dht11_init();			  //DHT11初始化
uint8 dht11_read_data();    //刷新数据（不建议连续多次读取传感器，每次读取传感器间隔大于2秒即可获得准确的数据）

float dht11_read_temp();//读温度
uint8 dht11_read_humidity();//读湿度

float dht11_read_temp_manual();//手动刷新读温度
uint8 dht11_read_humidity_manual();//手动刷新读湿度

//========================================================================
// 描述: DHT11读1字节数据.
// 参数: none.
// 返回: 读出的数据.
//========================================================================
uint8  DHT11_readvalue()
{
    uint8 i;
    uint8 value = 0,dht11_retry;
    for(i = 0; i < 8;i ++)
    {
        value<<=1;
        dht11_retry = 0;  
        while(DHT11_DQ == 0 && dht11_retry ++ < 50)  //读取每一数据位初始低电平为50us
		{
			#if defined (_C51)
			_nop_();
			#else
			delay1us();
			#endif
		}
        if(dht11_retry >= 50)
        {
            return 0;
        }
        delay10us();
        delay10us();
        delay10us();
        if(DHT11_DQ != 0)
        {
            value ++;
            dht11_retry = 0;
            while(DHT11_DQ != 0 && dht11_retry++ < 40) //读取一数据位为1，高电平为（40 + 30）us
			{
				#if defined (_C51)
				_nop_();
				#else
				delay1us();
				#endif
			}
            if(dht11_retry >= 40)
            {
                return 0;
            }
        }
    }
    return value;
}

//========================================================================
// 描述: DHT11刷新数据.
// 参数: none.
// 返回: 成功返回0，失败返回1.
//========================================================================
uint8 dht11_read_data()     
{
	uint8 dht11_retry = 0;
    uint8 i;
    
    DHT11_DQ = 1;
    DHT11_DQ = 0; 
    delay(20);    //主机拉低18ms设置起始信号     
    DHT11_DQ = 1;
	delay10us();     //主机拉高并延时等待
	delay10us();
    delay10us();
    delay10us();
    if(DHT11_DQ != 0)
    {
        return 1;	//返回错误代码
    }
    else
    {
        while(DHT11_DQ == 0 && dht11_retry ++ < 80)   //从机拉高80us响应
		{
				#if defined (_C51)
				_nop_();
				#else
				delay1us();
				#endif
		}
        if(dht11_retry >= 80)
        {
            return 2;	//返回错误代码
        }
        DHT11_DQ = 1;
        dht11_retry = 0;
        while(DHT11_DQ !=0 && dht11_retry ++ < 80)   //从机拉高延时准备输出
		{
			#if defined (_C51)
			_nop_();
			#else
			delay1us();
			#endif
		}
        if(dht11_retry >= 80)
        {
            return 3;	//返回错误代码
        }
        
        for(i = 0; i < 5 ; i ++)      //读取温湿度值
        {
            _dht11_arry_value[i] = DHT11_readvalue();
        }
        if(_dht11_arry_value[4] != (uint8)((_dht11_arry_value[0]+_dht11_arry_value[1]+_dht11_arry_value[2]+_dht11_arry_value[3])&0xff))    //比较读取结果
        {
            return 4;	//返回错误代码
        }
    }
    return  0;	
}

//========================================================================
// 描述: DHT11初始化.
// 参数: none.
// 返回: 识别到DHT11返回0，否则返回1.
//========================================================================
uint8 dht11_init()
{
	#ifndef    _C51
    DHT11_DQ_MODE;
	#endif
    DHT11_DQ = 1;    
    DHT11_DQ = 1; 
    DHT11_DQ = 0;                  // 主机发送开始工作信号
    delay(20);                     //延时18ms以上
    DHT11_DQ = 1; 
    delay10us();     //主机拉高并延时等待
	delay10us();
    delay10us();
    delay10us();
    if(DHT11_DQ != 0)
	{
		return 1;
	}else{
		return 0;
	}
}

//========================================================================
// 描述: DHT11读湿度（自动刷新，同时读温度和湿度数据有问题，所以同时只能读一个）.
// 参数: none.
// 返回: 湿度值
//========================================================================
uint8 dht11_read_humidity()
{
	if(dht11_read_data() == 0)	//刷新数据
	{
		return _dht11_arry_value[0];
	}
	else
	{
		return 255;	//读取湿度失败
	}
}

//========================================================================
// 描述: DHT11读温度（自动刷新，同时读温度和湿度数据有问题，所以同时只能读一个）.
// 参数: none.
// 返回: 温度值
//========================================================================
float dht11_read_temp()
{
	float f;
	if(dht11_read_data() != 0)	//刷新数据
	{
		return 255;	//读取温度失败
	}
	f = _dht11_arry_value[2] & 0x7F;
    f *= 10;
    f += _dht11_arry_value[3];
    f /= 10;
    if (_dht11_arry_value[2] & 0x80)
        f *= -1;
	return f;
}

//========================================================================
// 描述: DHT11读湿度（需手动使用刷新函数，温湿度可同时使用）.
// 参数: none.
// 返回: 湿度值
//========================================================================
uint8 dht11_read_humidity_manual()
{
	return _dht11_arry_value[0];
}

//========================================================================
// 描述: DHT11读温度（需手动使用刷新函数，温湿度可同时使用）.
// 参数: none.
// 返回: 温度值
//========================================================================
float dht11_read_temp_manual()
{
	float f;
	f = _dht11_arry_value[2] & 0x7F;
    f *= 10;
    f += _dht11_arry_value[3];
    f /= 10;
    if (_dht11_arry_value[2] & 0x80)
        f *= -1;
	return f;
}

#endif		//dht11.h